package com.healthcloud.service.accompany.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.IdcardUtil;
import cn.hutool.core.util.StrUtil;
import com.healthcloud.dao.accompany.AccompanyBlNoMedicalDao;
import com.healthcloud.dto.req.accompany.AccompanyBlFirstFromHospImportDTO;
import com.healthcloud.dto.req.accompany.AccompanyBlFirstImportDTO;
import com.healthcloud.dto.req.accompany.AccompanyBlMonth12ImportDTO;
import com.healthcloud.dto.req.accompany.AccompanyBlMonth18ImportDTO;
import com.healthcloud.dto.req.accompany.AccompanyBlMonth24ImportDTO;
import com.healthcloud.dto.req.accompany.AccompanyBlMonth6ImportDTO;
import com.healthcloud.entity.HlDoctorEntity;
import com.healthcloud.entity.PpPatientBaseEntity;
import com.healthcloud.entity.accompany.AccompanyBlEntity;
import com.healthcloud.entity.accompany.AccompanyBlNoMedicalEntity;
import com.healthcloud.enums.AccompanyBlHasMedicalFlagEnum;
import com.healthcloud.enums.AccompanyBlNoMedicalTypeEnum;
import com.healthcloud.enums.DelFlagEnum;
import com.healthcloud.enums.DiseaseTypeEnum;
import com.healthcloud.service.HlDoctorService;
import com.healthcloud.service.PpPatientBaseService;
import com.healthcloud.service.accompany.AccompanyBlNoMedicalService;
import com.healthcloud.service.accompany.AccompanyBlService;
import com.healthcloud.utils.ApiRes;
import com.healthcloud.utils.DateUtils;
import com.healthcloud.utils.ShiroUtils;
import com.healthcloud.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * 骨松随访-没有用药-区分首次、6、12、18、24个月 服务层实现
 *
 * @author liujx
 * @date 2020-08-03
 */
@Service
public class AccompanyBlNoMedicalServiceImpl implements AccompanyBlNoMedicalService {

    @Autowired
    private AccompanyBlNoMedicalDao accompanyBlNoMedicalDao;

    @Autowired
    private PpPatientBaseService ppPatientBaseService;

    @Autowired
    private HlDoctorService hlDoctorService;

    @Autowired
    private AccompanyBlService accompanyBlService;

    /**
     * 查询骨松随访-没有用药-区分首次、6、12、18、24个月信息
     *
     * @param id 骨松随访-没有用药-区分首次、6、12、18、24个月ID
     * @return 骨松随访-没有用药-区分首次、6、12、18、24个月信息
     */
    @Override
    public AccompanyBlNoMedicalEntity selectAccompanyBlNoMedicalById(Long id) {
        return accompanyBlNoMedicalDao.selectAccompanyBlNoMedicalById(id);
    }

    /**
     * 查询骨松随访-没有用药-区分首次、6、12、18、24个月列表
     *
     * @param accompanyBlNoMedical 骨松随访-没有用药-区分首次、6、12、18、24个月信息
     * @return 骨松随访-没有用药-区分首次、6、12、18、24个月集合
     */
    @Override
    public List<AccompanyBlNoMedicalEntity> selectAccompanyBlNoMedicalList(AccompanyBlNoMedicalEntity accompanyBlNoMedical) {
        return accompanyBlNoMedicalDao.selectAccompanyBlNoMedicalList(accompanyBlNoMedical);
    }

    /**
     * 修改骨松随访-没有用药-区分首次、6、12、18、24个月
     *
     * @param accompanyBlNoMedical 骨松随访-没有用药-区分首次、6、12、18、24个月信息
     * @return 结果
     */
    @Override
    public int updateAccompanyBlNoMedical(AccompanyBlNoMedicalEntity accompanyBlNoMedical) {
        return accompanyBlNoMedicalDao.updateAccompanyBlNoMedical(accompanyBlNoMedical);
    }

    /**
     * 删除骨松随访-没有用药-区分首次、6、12、18、24个月对象
     *
     * @param ids 需要删除的数据ID
     * @return 结果
     */
    @Override
    public int deleteAccompanyBlNoMedicalByIds(String ids) {
        return accompanyBlNoMedicalDao.deleteAccompanyBlNoMedicalByIds(Convert.toStrArray(ids));
    }

    /**
     * 将骨松筛查及首次问卷excel数据添加到 db 中
     *
     * @param list
     * @return
     */
    @Override
    public ApiRes importExcelFirstData(List<AccompanyBlFirstImportDTO> list) throws Exception {
        return this.importExcelData(list, AccompanyBlNoMedicalTypeEnum.FIRST.getCode());
    }

    /**
     * 将骨松筛查及首次问卷excel数据添加到 db 中
     *
     * @param list
     * @return
     */
    @Override
    public ApiRes importExcelFirstDataForHosp(List<AccompanyBlFirstFromHospImportDTO> list) throws Exception {
        return this.importExcelData(list, AccompanyBlNoMedicalTypeEnum.FIRST.getCode());
    }

    /**
     * 将6个月随访问卷excel数据添加到 db 中
     *
     * @param list
     * @return
     */
    @Override
    public ApiRes importExcelMonth6Data(List<AccompanyBlMonth6ImportDTO> list) throws Exception {
        return this.importExcelData(list, AccompanyBlNoMedicalTypeEnum.MONTH_6.getCode());
    }

    /**
     * 将12个月随访问卷数据添加到 db 中
     *
     * @param list
     * @return
     */
    @Override
    public ApiRes importExcelMonth12Data(List<AccompanyBlMonth12ImportDTO> list) throws Exception {
        return this.importExcelData(list, AccompanyBlNoMedicalTypeEnum.MONTH_12.getCode());
    }

    /**
     * 将18个月随访问卷数据添加到 db 中
     *
     * @param list
     * @return
     */
    @Override
    public ApiRes importExcelMonth18Data(List<AccompanyBlMonth18ImportDTO> list) throws Exception {
        return this.importExcelData(list, AccompanyBlNoMedicalTypeEnum.MONTH_18.getCode());
    }

    /**
     * 将24个月随访问卷数据添加到 db 中
     *
     * @param list
     * @return
     */
    @Override
    public ApiRes importExcelMonth24Data(List<AccompanyBlMonth24ImportDTO> list) throws Exception {
        return this.importExcelData(list, AccompanyBlNoMedicalTypeEnum.MONTH_24.getCode());
    }

    /**
     * 将 excel 数据添加到 db 中 accompany_bl_no_medical
     *
     * @param list          待新增的 list
     * @param accompanyType 随访类型：0-首次问卷；1-6个月随访；2-12个月随访；3-18个月随访；4-24个月随访
     * @return todo 确保说在新的随访记录表 accompany_bl_no_medical 中，
     * 一位患者在不同阶段（首次、6、12、18、24个月）的随访过程中，填写的手机号必须一致；6、12、18、24个月需要根据首次填写的手机号进行匹配；
     * 但不能保证 accompany_bl_no_medical 和 pp_patient_base 中，同一身份证患者的手机号一致。
     * <p>
     */
    @Transactional(rollbackFor = Exception.class)
    public ApiRes importExcelData(List list, Integer accompanyType) {
        LocalDateTime now = LocalDateTime.now();
        Date date = new Date();

        if (CollUtil.isEmpty(list)) {
            return ApiRes.failure("导入失败，没有需要导入的数据。");
        }

        /// 获取本医院id和医生id
        Long hospitalId = null;
        Long doctorId = null;
        if (ShiroUtils.getUserId() != 5) {
            HlDoctorEntity hlDoctorEntity = hlDoctorService.queryByUserId(ShiroUtils.getUserId());
            if (hlDoctorEntity == null) {
                return new ApiRes(false, null, "登录账号非医生账号", "登录账号非医生账号");
            }
            hospitalId = hlDoctorEntity.getHospId();
            doctorId = hlDoctorEntity.getId();
        }

        int addCount = 0;
        for (Object temp : list) {
            AccompanyBlNoMedicalEntity entity = new AccompanyBlNoMedicalEntity();
            BeanUtil.copyProperties(temp, entity);

            // 调查日期-年 为空，说明是空行，无用数据，直接 continue
            if (StrUtil.isBlankIfStr(entity.getDateYear())) {
                continue;
            }

            entity.setBlNoMedicalType(accompanyType);
            entity.setHospitalId(hospitalId);
            entity.setCreateTime(now);
            entity.setUpdateTime(now);
            entity.setDeleted(DelFlagEnum.NORMAL.getCode());

            Assert.notBlank(entity.getPatientName());
            /*if (StrUtil.isBlank(entity.getPatientPhone())) {
                return ApiRes.failure("导入失败。" + entity.getPatientName() + "患者手机号不能为空。");
            }*/

            /// 首次，患者身份证号不能为空
            if (AccompanyBlNoMedicalTypeEnum.FIRST.getCode().equals(accompanyType)) {
                if (StrUtil.isBlank(entity.getIdCard())) {
                    return ApiRes.failure("导入失败。" + entity.getPatientName() + "首次随访：患者身份证号不能为空。");
                }

                // 验证身份证号
                boolean validCard = IdcardUtil.isValidCard(entity.getIdCard());
                if (!validCard) {
                    return ApiRes.failure("导入失败。首次随访：患者" + entity.getIdCard() + "身份证号不能合法。");
                }

                /// 根据身份证号、hospitalId，查询 pp_patient_base 患者表中是否已有记录。没有，则添加患者
                int existCount = ppPatientBaseService.countByIdCardAndHospitalId(entity.getIdCard(), hospitalId);
                if (existCount == 0) {
                    // 新增骨松患者到 pp_patient_base
                    this.addPatientByBLExcel(entity, doctorId);
                }

            } else {
                /// 非首次，也就是6、12、18、24个月的随访数据
                /// 此时没有身份证号，需要根据患者手机号，来查询对应的身份证号。查询不到，则不导入，提示「未在以往随访记录中匹配到该患者身份证号。」

                // 根据患者手机号，来查询对应的身份证号。
                List<String> idCardList = accompanyBlNoMedicalDao.listByPatientPhone(entity.getPatientPhone(), hospitalId);
                if (CollUtil.isEmpty(idCardList)) {
                    return ApiRes.failure("导入失败。未在以往随访记录中匹配到" + entity.getPatientName() + "身份证号。");
                }
                entity.setIdCard(idCardList.get(0));
            }

            // 有则假删，然后新增
            /// 根据患者身份证号、医院id、随访类型，删除以前的骨松随访记录 accompany_bl
            List<Long> accompanyBLIds = accompanyBlNoMedicalDao.getAccompanyBLId(entity);
            if (CollUtil.isNotEmpty(accompanyBLIds)) {
                accompanyBlService.deleteByIds(accompanyBLIds);
            }
            /// 根据患者身份证号、医院id、随访类型，逻辑删除以前的无药物随访记录 accompany_bl_no_medical
            accompanyBlNoMedicalDao.removeAccompanyData(entity);

            // 本次随访日期
            String dateYear = StringUtils.fillZero(entity.getDateYear(), 4);
            String dateMonth = StringUtils.fillZero(entity.getDateMonth(), 2);
            String dateStr = StringUtils.fillZero(entity.getDateDay(), 2);
            String accompanyTimeStr = dateYear + "-" + dateMonth + "-" + dateStr + " 00:00:00";

            /// 添加到原来的骨松随访记录表 accompany_bl
            Long accompanyBlId = this.addAccompanyBlByExcel(entity, doctorId, accompanyTimeStr);

            entity.setAccompanyBlId(accompanyBlId);
            entity.setAccompanyTime(DateUtils.toLocalDateTime(accompanyTimeStr));
            accompanyBlNoMedicalDao.save(entity);

            addCount += 1;
        }

        return ApiRes.success("导入成功。共计导入" + addCount + "条记录。");
    }

    private Long addAccompanyBlByExcel(AccompanyBlNoMedicalEntity entity, Long doctorId, String accompanyTimeStr) {
        Date date = new Date();

        // 本次随访日期
        Date accompanyDate = DateUtil.parseDateTime(accompanyTimeStr);

        // 下次随访日期：按照首次、6、12、18、24个月这种节奏来，下次是 +6个月
        Calendar c = Calendar.getInstance();
        c.setTime(accompanyDate);
        c.add(Calendar.DATE, 30 * 6);
        Date nextAccompanyTime = c.getTime();

        AccompanyBlEntity accompanyBlEntity = AccompanyBlEntity.builder()
                .idCard(entity.getIdCard())
                .accompanyTime(accompanyDate)
                .nextAccompanyTime(nextAccompanyTime)
                .accompanyType(1) // 门诊
                .hasMedical(AccompanyBlHasMedicalFlagEnum.NO_MEDICAL.getCode()) // 没有药物
                .doctorId(doctorId)
                .checkTime(accompanyDate)
                .createTime(date)
                .updateTime(date)
                .remark(null != entity.getBlNoMedicalType() ? entity.getBlNoMedicalType().toString() : "")
                .build();
        accompanyBlService.save(accompanyBlEntity);
        return Long.valueOf(accompanyBlEntity.getId().toString());
    }

    /**
     * 骨松随访 添加患者
     * <p>
     * 参照接口 /pppatientbase/addRecord
     *
     * @param entity
     */
    private void addPatientByBLExcel(AccompanyBlNoMedicalEntity entity, Long doctorId) {
        Date date = new Date();

        // 性别：1-男；2-女
        Integer gender = null;
        if (StrUtil.isNotBlank(entity.getPatientGender())) {
            if (entity.getPatientGender().contains("男")) {
                gender = 1;
            }
            if (entity.getPatientGender().contains("女")) {
                gender = 2;
            }
        }

        PpPatientBaseEntity patient = PpPatientBaseEntity.builder()
                .doctorId(doctorId)
                .hospitalId(entity.getHospitalId())
                .realname(entity.getPatientName().trim())
                .idcard(entity.getIdCard().trim())
                .phone(StrUtil.isNotEmpty(entity.getPatientPhone()) ? entity.getPatientPhone().trim() : "")
                .gender(gender)
                .registeraddress(StrUtil.isNotBlank(entity.getProvince()) ? entity.getProvince().trim() : "")
                .career(StrUtil.isNotBlank(entity.getJob()) ? entity.getJob().trim() : "")
                .homeaddress(StrUtil.isNotBlank(entity.getAddress()) ? entity.getAddress().trim() : "")
                .createdtime(date)
                .updatedtime(date)
                .sourceType(1)
                .diseasesType(DiseaseTypeEnum.BL.getCode().toString()) // 骨松人群
                .height(Double.valueOf(entity.getHeight().trim()))
                .weight(Double.valueOf(entity.getWeight().trim()))
                .remark("骨松随访excel数据导入添加")
                .build();

        ppPatientBaseService.savePatient(patient);
    }

    /**
     * 保存无药物骨松随访（新增/修改）
     * <p>
     * 没有 id，则新增；
     * 有 id，则修改
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ApiRes saveOrUpdate(AccompanyBlNoMedicalEntity entity) {

        /// 获取本医院id和医生id
        Long hospitalId = null;
        Long doctorId = null;
        if (ShiroUtils.getUserId() != 5) {
            HlDoctorEntity hlDoctorEntity = hlDoctorService.queryByUserId(ShiroUtils.getUserId());
            if (hlDoctorEntity == null) {
                return new ApiRes(false, null, "登录账号非医生账号", "登录账号非医生账号");
            }
            hospitalId = hlDoctorEntity.getHospId();
            doctorId = hlDoctorEntity.getId();
        }

        LocalDateTime now = LocalDateTime.now();
        entity.setUpdateTime(now);

        // entity.set
        if (null == entity.getId()) {
            /// 新增

            // accompany_bl
            // 本次随访日期
            String yyyyMMddStr = DateUtils.toLocalDateTimeStr(entity.getAccompanyTime(), DatePattern.NORM_DATE_PATTERN);
            String accompanyTimeStr = yyyyMMddStr + " 00:00:00";

            /// 添加到原来的骨松随访记录表 accompany_bl
            Long accompanyBlId = this.addAccompanyBlByExcel(entity, doctorId, accompanyTimeStr);

            // accompany_bl_no_medical
            entity.setAccompanyBlId(accompanyBlId);
            entity.setHospitalId(hospitalId);
            entity.setDeleted(DelFlagEnum.NORMAL.getCode());
            entity.setCreateTime(now);
            accompanyBlNoMedicalDao.save(entity);

        } else {
            /// 修改
            // accompany_bl
            // accompany_bl_no_medical
            accompanyBlNoMedicalDao.updateAccompanyBlNoMedical(entity);
        }
        return ApiRes.success();
    }

    /**
     * 查询骨松随访-没有用药-区分首次、6、12、18、24个月信息
     */
    @Override
    public AccompanyBlNoMedicalEntity queryByAccompanyBlId(Long accompanyBlId) {
        return accompanyBlNoMedicalDao.queryByAccompanyBlId(accompanyBlId);
    }

    /**
     * 根据 accompany_bl_id 列表，逻辑删除无药物骨松随访
     */
    @Override
    public int batchRemoveByAccompanyBlIds(Long[] accompanyBlIds) {
        return accompanyBlNoMedicalDao.batchRemoveByAccompanyBlIds(accompanyBlIds);
    }

}